﻿/*
 * @Autor: PK
 * @Date: 2021/12/26 10:20:SS
 */

using System;
using System.Collections.Generic;
using O2DESNet;
using ShkSimulation.core.exceptions;

namespace ShkSimulation.core.dao.statistic {

	public class DataReportInfo {

		private SortedSet<string> uniqueKeySet = new SortedSet<string>();

		private Dictionary<string, ReadOnlyHourCounter> hourCounterData = new Dictionary<string, ReadOnlyHourCounter>();

		private Dictionary<string, double> doubleData = new Dictionary<string, double>();

		public List<string> DataUniqueKeys => new List<string>(uniqueKeySet);

		public HashSet<string> DoubleUniqueKeys => new HashSet<string>(doubleData.Keys);
		
		public HashSet<string> HourCounterUniqueKeys => new HashSet<string>(hourCounterData.Keys);

		public string ReporterUniqueKey { get; set; }

		public IReadOnlyDictionary<string, ReadOnlyHourCounter> HourCounterData => hourCounterData.AsReadOnly();
		
		public IReadOnlyDictionary<string, double> DoubleData => doubleData.AsReadOnly();

		public DateTime ReportTime { get; private set; }

		public void Add(string key, double value) {
			if (uniqueKeySet.Contains(key)) {
				throw new ErrorParamException($"不允许有重复的Key{key}");
			}
			uniqueKeySet.Add(key);
			doubleData.Add(key, value);
		}
		
		public void Add(string key, HourCounter hourCounter) {
			if (uniqueKeySet.Contains(key)) {
				throw new ErrorParamException($"不允许有重复的Key{key}");
			}
			uniqueKeySet.Add(key);
			hourCounterData.Add(key, hourCounter.AsReadOnly());
		}
		
		public void Add(string key, ReadOnlyHourCounter hourCounter) {
			if (uniqueKeySet.Contains(key)) {
				throw new ErrorParamException($"不允许有重复的Key{key}");
			}
			uniqueKeySet.Add(key);
			hourCounterData.Add(key, hourCounter);
		}

		public static DataReportInfo Create(string uniqueKey, DateTime reportTime,
			Dictionary<string, ReadOnlyHourCounter> hourCounterValue = null,
			Dictionary<string, double> doubleValue = null) {
			DataReportInfo info = new DataReportInfo();

			info.uniqueKeySet = new SortedSet<string>();
			if (hourCounterValue != null) {
				foreach (var key in hourCounterValue.Keys) {
					info.uniqueKeySet.Add(key);
				}
			}
			if (doubleValue != null) {
				foreach (var key in doubleValue.Keys) {
					if (info.uniqueKeySet.Contains(key)) {
						throw new ErrorParamException($"不允许有重复的Key{key}");
					}
					info.uniqueKeySet.Add(key);
				}
			}
			info.hourCounterData = hourCounterValue != null? 
				new Dictionary<string, ReadOnlyHourCounter>(hourCounterValue): new Dictionary<string, ReadOnlyHourCounter>();
			info.doubleData = doubleValue != null? 
				new Dictionary<string, double>(doubleValue): new Dictionary<string, double>();
			info.ReporterUniqueKey = uniqueKey;
			info.ReportTime = reportTime;
			return info; 
		}

		public static DataReportInfo Empty() {
			return new DataReportInfo();
		}

		public double GetDoubleValue(string key) {
			if (doubleData != null && doubleData.ContainsKey(key)) {
				return doubleData[key];
			}
			throw new ErrorParamException($"参数未找到{key}");
		}
		
		public ReadOnlyHourCounter GetHourCounter(string key) {
			if (hourCounterData != null && hourCounterData.ContainsKey(key)) {
				return hourCounterData[key];
			}
			throw new ErrorParamException($"参数未找到{key}");
		}
		
		public DataReportInfo Merge(DataReportInfo info2) {
			// 内部服务台采取的合并模式，是加key还是相同的key直接加起来
			Dictionary<string, double> doubleValues = info2.doubleData ?? new Dictionary<string, double>();
			Dictionary<string, ReadOnlyHourCounter> hourCounters = info2.hourCounterData ?? new Dictionary<string, ReadOnlyHourCounter>();
			foreach (var (key, value) in doubleValues) {
				if (!doubleData.ContainsKey(key)) {
					doubleData[key] = value;
				} else {
					string hourKey = $"{key}#{info2.ReporterUniqueKey}";
					doubleData[hourKey] += value;
				}
			}
			foreach (var (key, readOnlyHourCounter) in hourCounters) {
				if (!hourCounterData.ContainsKey(key)) {
					hourCounterData[key] = readOnlyHourCounter;
				} else {
					string hourKey = $"{key}#{info2.ReporterUniqueKey}";
					hourCounterData[hourKey] = readOnlyHourCounter;
				}
			}
			return this;
		}

		public static DataReportInfo Merge(DataReportInfo info1, DataReportInfo info2) {
			return info1.Merge(info2);
		}

	}

}